# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cgi
import sys
import datetime
import time
import logging
from google.appengine.api import users
import google.appengine.api
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp.util import run_wsgi_app

from django.utils import simplejson

class AppController(webapp.RequestHandler):
  """ this class handle all requests from /req and output json string.
  
  """

  def setConfig(self,config):
    self.configFile = config
    
  def setCommandModule(self,commands):
    self.commands = commands
  
  def get(self):
    self.handle()
    
  def post(self):
    self.handle()
    
  def handle(self):
    self.request.headers['CharacterEncoding'] = 'UTF-8'
    (ctn,vid,oid) = self.authendicate(self.request)
    
    self.config = ConfigFactory(self.configFile).load()
    self.context = AppContext(self.request,self.response,self.config)
    self.context.update({"ctn":ctn,"vid":vid,"oid":oid})
    
    commandName = self.request.get("cmd")
    command = CommandFactory(self.commands).load(commandName)
    
    result = command.executeWithContext(self.context)
    self.response.headers['CharacterEncoding'] = 'UTF-8'
    self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
    output = self.context["output"]
    
    self.response.out.write(BeanJsonConverter.convertToString(output))
	
  def authendicate(self,request):
    if(request.get("ctn") and request.get("vid") and request.get("oid")):
      return (request.get("ctn"),request.get("vid"),request.get("oid"));
    else:
      #TODO : is sytax right?
      raise AttributeError,"parameters not sufficient"
  
class AppContext(dict):
  """ this class include context used in command
  
  """
  def __init__(self,request,response,config):
    self.request = request
    self.response = response
    self.config = config
    
class ConfigFactory:
  """ this class read specific configuration of every container
  """
  def __init__(self,config):
    self.config = config
  
  def load(self,container="default"):
    return self.config[container]
  
class CommandFactory:
  """this class load command from catalog config file
  """
  def __init__(self,commands):
    self.commands = commands
  
  def load(self,commandName):
    try:
      command = getattr(self.commands,commandName + "Command")
      return command()
    except AttributeError:
      #TODO : look for catalog config
      c = getattr(self.commands,"catalog")
      command = getattr(self.commands,c[commandName] + "Command")
      return command()

class ResponseItem:
  def __init__(self):
    self.hasError = True
    self.data = None
    
class Message:
  def __init__(self,messageId,params):
    self.messageId = messageId
    self.params = params

class ModelEncoder(simplejson.JSONEncoder):
  """used to encode model object
  """
  def default(self, obj):
    if isinstance(obj, db.Model):
      d = {"id":obj.key().id()}
      d.update(obj.__dict__['_entity'])
      return d
    if isinstance(obj,db.GqlQuery) or isinstance(obj,db.Query):
      return [item for item in obj]
    if isinstance(obj,google.appengine.api.datastore_types.Key):
      return db.Model.get(obj)
    if isinstance(obj,ResponseItem):
      return obj.__dict__
    if isinstance(obj,Message):
      return obj.__dict__
    if isinstance(obj,datetime.datetime):
      ts = time.mktime(obj.timetuple())
      ts = int(ts * 1000 + obj.microsecond / 1000)
      return int(ts)
    
    return str(type(obj))
    #return simplejson.JSONEncoder.default(self, obj)

class BeanJsonConverter:
  """ this class converter object to json string
  """
  @staticmethod
  def convertToString(obj):
    return simplejson.dumps(obj,cls=ModelEncoder)

class Command:
  NEXT = False
  END = True

  def pre(self,context):
    self.responseItem = ResponseItem()
    self.request = context.request
    self.response = context.response
    self.config = context.config
    self.context = context
    context["output"] = self.responseItem
    
    return self.NEXT
  
  def output(self,data):
    self.responseItem.data = data
  
  def hasError(self,flag):
    self.responseItem.hasError = flag
  
  def executeWithContext(self,context):
    if(self.pre(context) == self.NEXT):
      return self.execute()
    else:
      return self.END
  
  def execute(self):
    raise NotImplementedError
